from abstract_node.definition import AbstractNode
from abstract_node.output_interfaces import OutputInterfaceToFAMOUSO
from abstract_node.output_interfaces import OutputInterfaceToConsole
from abstract_node.output_interfaces import OutputInterfaceToVTK
from abstract_node.output_layer import AbstractOutputLayer
from abstract_sensor.input_layer import AbstractInputLayer

class SmartAbstractSensor(AbstractNode):

    def __init__(self, outputDataSheet, sensor_interface, appName, outputLayer=[], logger=[]):
        # Definition of a default network in case of missing user defined output
        # functions
        if outputLayer!=[]:
            AbstractNode.__init__(self, 
                                  eventDataSheet=outputDataSheet,
                                  appName=appName,
                                  outputLayer=outputLayer,
                                  logger=logger)
        else:
            # Standard Output Definition of the Abstract Sensor Node
            MyNetworkOutput=OutputInterfaceToFAMOUSO(outputDataSheet)
            MyConsolOutput=OutputInterfaceToConsole(outputDataSheet)
            
            MyAbstractOutputLayer=AbstractOutputLayer([MyNetworkOutput, 
                                                       MyConsolOutput])
            AbstractNode.__init__(self, 
                                  eventDataSheet=outputDataSheet,
                                  appName=appName,
                                  outputLayer=MyAbstractOutputLayer,
                                  logger=logger) 
               
        self.sensorProperties=sensor_interface.getproperties()
        if self.channelProperties.period!=0:
            self.input_layer = AbstractInputLayer(sensor_interface,
                                                  mapping_fct=self.input_event_mapping,
                                                  filtering_fct=self.input_event_filtering)           
        else:                
            self.input_layer = AbstractInputLayer(sensor_interface,
                                                  mapping_fct=self.input_event_mapping,
                                                  filtering_fct=self.input_event_filtering,
                                                  trigger_fct=self.dispatcher.trigger)


    def startMeasurements(self):
        self.input_layer.start_measurements()
        
    def stopMeasurements(self):
        self.input_layer.stop_measurements()

    def __repr__(self):
        output= "\n-----------------------------------------------------\n"
        output+="Application name     %s\n"%self.appName
        output+= "Output Subject       \"%s\"" %self.channelProperties.subject
        if self.channelProperties.period!=0:
            output+=" (Period %s) \n" %self.channelProperties.period
        else:
            output+=" (Event based publication)\n"
        output+="-----------------------------------------------------\n"
        output+="Channel Datasheet    %s\n" %self.channelProperties.channelDataSheet    
        output+="Format               %s entries\n"%(len(self.channelProperties.eventFormat))
        for entry in self.channelProperties.eventFormat:
            output+="                     {0:12}".format(entry["Name"])
            output+=" - {0:8}".format(entry["DataType"])
            output+=" - {0:2} ".format(entry["Size"])
            if entry["Static"]==True:
                output+="- static\n"
            else:
                output+="- variable\n"
        output+="-----------------------------------------------------\n"
        if self.sensorProperties.sensorDataSheet!=[]:
            output+="Sensor Datasheet     %s \n" %self.sensorProperties.sensorDataSheet
            output+="Format               %s entries\n"%(len(self.sensorProperties.eventFormat))
        for entry in self.sensorProperties.eventFormat:
            output+="                     {0:12}".format(entry["Name"])
            output+=" - {0:8}".format(entry["DataType"])
            output+=" - {0:2} ".format(entry["Size"])
            if entry["Static"]==True:
                output+="- static\n"
            else:
                output+="- variable\n"
        if self.sensorProperties.omnidirectional==True:
            output+="                     Omnidirectional"        
        if self.sensorProperties.omnidirectional==False:
            output+="                     directed sensor - " 
        if self.sensorProperties.beams!=[]:
            output+="Sensor beams loaded (%d)\n"%len(self.sensorProperties.beams)
        output+="                     measurement period %s\n"% self.sensorProperties.period     
        
        return output
    
from PyQt4 import QtCore, QtGui
class VTKSmartAbstractSensor(SmartAbstractSensor, QtCore.QObject ):

    def __init__(self, outputDataSheet, sensor_interface, renderer, appName, outputLayer=[], logger=[]):
        
        import vtk
        from vtk.util.colors import red, green, blue
        
        QtCore.QObject.__init__(self)
        self.renderer=renderer
        if outputLayer==[]:
            # Standard Output Definition of the Abstract VTK Sensor Node
            MyNetworkOutput=OutputInterfaceToFAMOUSO(outputDataSheet)
            MyConsolOutput=OutputInterfaceToConsole(outputDataSheet)
            MyVTKOutput=OutputInterfaceToVTK(outputDataSheet,self)
                
            MyAbstractOutputLayer=AbstractOutputLayer([MyNetworkOutput, 
                                                       MyConsolOutput,
                                                       MyVTKOutput])         
        
            SmartAbstractSensor.__init__(self, 
                                         outputDataSheet=outputDataSheet,
                                         sensor_interface=sensor_interface,
                                         outputLayer=MyAbstractOutputLayer,
                                         appName = appName)
        else:
            SmartAbstractSensor.__init__(self, 
                                         outputDataSheet=outputDataSheet,
                                         sensor_interface=sensor_interface,
                                         appName = appName)
        
    def initSensorBeam(self):
        #Sensor
        if self.sensorProperties.omnidirectional==False:
            [xmin, xmax, ymin, ymax, zmin, zmax]=self.sensorProperties.getBeamMinMax()    
            SensorPoints = vtk.vtkPoints()
            SensorPoints.SetNumberOfPoints(8)
            SensorPoints.InsertPoint(0, xmin, -ymin, -zmin)
            SensorPoints.InsertPoint(1, xmax, -ymax, -zmax)
            SensorPoints.InsertPoint(2, xmax, ymax, -zmax)
            SensorPoints.InsertPoint(3, xmin, ymin, -zmin)
            SensorPoints.InsertPoint(4, xmin, -ymin, zmin)
            SensorPoints.InsertPoint(5, xmax, -ymax, zmax)
            SensorPoints.InsertPoint(6, xmax, ymax, zmax)
            SensorPoints.InsertPoint(7, xmin, ymin, zmin)
            Sensor = vtk.vtkHexahedron()
            Sensor.GetPointIds().SetId(0, 0)
            Sensor.GetPointIds().SetId(1, 1)
            Sensor.GetPointIds().SetId(2, 2)
            Sensor.GetPointIds().SetId(3, 3)
            Sensor.GetPointIds().SetId(4, 4)
            Sensor.GetPointIds().SetId(5, 5)
            Sensor.GetPointIds().SetId(6, 6)
            Sensor.GetPointIds().SetId(7, 7)
            SensorGrid = vtk.vtkUnstructuredGrid()
            SensorGrid.Allocate(1, 1)
            SensorGrid.InsertNextCell(Sensor.GetCellType(),
                                      Sensor.GetPointIds())
            SensorGrid.SetPoints(SensorPoints)
                
            SensorMapper = vtk.vtkDataSetMapper()
            SensorMapper.SetInput(SensorGrid)
                
            self.actSensor=vtk.vtkActor()
            self.actSensor.SetMapper(SensorMapper)
            
            self.actSensor.SetOrientation(self.orientation.magnitude)            
            self.actSensor.SetPosition(self.position.magnitude)           
            self.actSensor.GetProperty().SetOpacity(0.3)
            self.actSensor.GetProperty().SetColor(blue)
        else:
            srcSensor=vtk.vtkSphereSource()
            srcSensor.SetRadius(10)
            mapMeas=vtk.vtkPolyDataMapper();
            mapMeas.SetInput( srcSensor.GetOutput() )            
            self.actSensor = vtk.vtkActor()
            self.actSensor.SetMapper(mapMeas)
            self.actSensor.SetPosition(self.position[0].magnitude)
            self.actSensor.GetProperty().SetColor(green) 
                      
        self.renderer.AddActor(self.actSensor)
        self.redrawVTKSmartAbstractSensor() 

    def hideSensorBeam(self):
        self.stopMeasurements()
        self.actSensor.SetVisibility(False)  
        self.redrawVTKSmartAbstractSensor()   

    def initText(self):
        srcText = vtk.vtkVectorText()
        srcText.SetText(self.sensorProperties.name)
        textMapper = vtk.vtkPolyDataMapper()
        textMapper.SetInputConnection(srcText.GetOutputPort())
        self.actText = vtk.vtkFollower()
        if self.sensorProperties.omnidirectional==False:
            self.actText.SetPosition(self.position.magnitude)
        else:
            pos=self.position.magnitude
            self.actText.SetPosition(pos[0],pos[1],pos[2]+10)
        self.actText.SetMapper(textMapper)
        self.actText.AddPosition(0, -0.1, 0)
        self.actText.SetScale(10, 10, 10)
        self.actText.GetProperty().SetColor(blue) 
        self.actText.SetCamera(self.renderer.GetActiveCamera())
        
        self.renderer.AddActor(self.actText)
        self.redrawVTKSmartAbstractSensor() 
    
    def hideText(self):
        self.actText.SetVisibility(False)
        self.redrawVTKSmartAbstractSensor() 
        
    def initMeasurement(self):       
        srcMeas = vtk.vtkRegularPolygonSource()
        srcMeas.SetRadius(10)
        srcMeas.SetNumberOfSides(360)
           
        mapMeas=vtk.vtkPolyDataMapper();
        mapMeas.SetInput( srcMeas.GetOutput() )
          
        self.actMeas = vtk.vtkActor()
        self.actMeas.SetMapper(mapMeas)
        self.actMeas.SetPosition(0,0,0.1)
        self.actMeas.GetProperty().SetColor(green)
        self.actMeas.SetVisibility(False)  
        self.renderer.AddActor(self.actMeas)
        self.redrawVTKSmartAbstractSensor() 
        
    def showMeasurement(self, position):
        try:
            self.actMeas.SetPosition(position[0],position[1],0.1)
            self.actMeas.SetVisibility(True)
            self.redrawVTKSmartAbstractSensor() 
        except:
            print "GUI is not ready yet"

    def hideMeasurement(self):
        self.actMeas.SetVisibility(False)
        self.redrawVTKSmartAbstractSensor()   
        
    def getVTKSmartAbstractSensor(self):
        return self
    
    def redrawVTKSmartAbstractSensor(self):
        self.emit(QtCore.SIGNAL("updateGui( )"), )
